7. 递归的数据类型
递归与递归数据类型在编程中十分重要,许多常见的数据结构都是递归定义的。
递归数据结构的定义包括两部分:
- 基本情形指明该数据类型的某些不依赖递归定义得到的基本元素;
- 构造情形指明如何由已知的基本元素或构建的元素来构造新的元素。
类似的,定义在这些递归数据类型上的方法也是递归定义的:你需要定义该方法在所有基本情形上的值,然后定义在构造情形中,如何基于已知的方法的值得到新的值。
当数据类型的递归定义允许通过多种方式得到同一个元素时,我们称这种定义方法是 模棱两可 的。实际定义递归数据结构类型时要尽可能避免模棱两可的定义,因为这极有可能导致在该数据类型上定义的递归方法存在歧义。见下面这个例子:
我们尝试以如下递归方法定义
- 基本情形:
- 构造情形:若
,则
我们再定义如下方法
- 基本情形:
- 构造情形:若
,则
这个定义乍看之下没有问题,但很容易就能发现
然而并非所有定义在模棱两可的递归类型上的方法都存在歧义。例如将上面的方法的构造定义修改为类似取对数的运算
为了证明递归数据结构具有某些性质,可以使用 结构归纳法。结构归纳法与上面递归方法的定义过程与前面提到的 状态机上的归纳法 十分相像。其基本过程为:
设
为真 - 对含有
个参数的构造方法 ,有
则对于任意
我们可以使用递归来定义非负整数集
- 基本情形:
- 递归情形:如果
,则
如果我们在该非负整数集的定义上应用结构归纳法,会发现它和前面讲过的 一般归纳法 完全一致,这表明,一般归纳法是结构归纳法的特例。
然而需要注意的是,有些递归方法会使用较大的参数对应的函数值来定义较小的参数对应的函数值,这些递归方法无法使用结构归纳法来判断其性质,这些方法的递归可能无法终止,但并不绝对。例如这两个定义在
- Collatz 猜想,又称冰雹猜想:
关于该函数一个著名猜想是
- 阿克曼函数:
阿克曼函数增长极快,对应的,其反函数